package edu.unicauca.opentextbook.controladores;

import edu.unicauca.opentextbook.controladores.util.JsfUtil;
import edu.unicauca.opentextbook.entidades.Tarea;
import edu.unicauca.opentextbook.entidades.Usuario;
import edu.unicauca.opentextbook.entidades.VotosTarea;
import edu.unicauca.opentextbook.fachadas.LibroFacade;
import edu.unicauca.opentextbook.fachadas.TareaFacade;
import edu.unicauca.opentextbook.fachadas.UsuarioFacade;
import edu.unicauca.opentextbook.fachadas.VotosTareaFacade;
import edu.unicauca.opentextbook.negocio.VotosTareaNegocio;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.primefaces.push.PushContext;
import org.primefaces.push.PushContextFactory;

@ManagedBean(name = "tareaController")
@ViewScoped
public class TareaController extends BaseController implements Serializable {

    //LOG
    private static final Log LOG = LogFactory
            .getLog(TareaController.class.getName());
    //Controladores
    @ManagedProperty("#{canalesController}")
    private CanalesController canalesController;
    @ManagedProperty("#{loginController}")
    private LoginController loginController;
    //EJBs
    @EJB
    private TareaFacade tareaFacade;
    @EJB
    private UsuarioFacade usuarioFacade;
    @EJB
    private LibroFacade libroFacade;
    @EJB
    private VotosTareaFacade votosTareaFacade;
    //Objetos
    private Tarea tarea;
    //Listas
    private List<Tarea> listaTareas;
    private List<Tarea> listaTareasPorCubrir;
    private List<VotosTarea> listaVotosTareas;
    //Variables
    private String canal;

    //Metodos
    @PostConstruct
    public void init() {
        LOG.info("Dentro de init TareaController...");
        tarea = new Tarea();
        listaVotosTareas = new ArrayList<VotosTarea>();
        obtenerParametro();
        consultarTareas();
        cargarTareasPorCubrir();
        registrarCanal();
    }

    private void obtenerParametro() {
        final FacesContext facesContext = FacesContext.getCurrentInstance();
        final Map params = facesContext.getExternalContext().getRequestParameterMap();
        final int idLibro = Integer.parseInt(params.get("libro").toString());

        tarea.setLibro(libroFacade.buscarLibro(idLibro));

    }

    public void consultarTareas() {
        LOG.info("Dentro de consultarTareas...");
        listaTareas = tareaFacade.consultarTareasPorLibro(tarea.getLibro().getIdLibro());
    }

    public void registrarTarea() {
        final Usuario usuario = usuarioFacade.buscarUsuarioPorNick(loginController.getNick());

        tarea.setUsuario(usuario);
        tarea.setFecha(new Date());

        try {
            userTransaction.begin();

            tareaFacade.create(clonarObjeto(tarea));
            commitTransaction();

            comunicarseConCanalDeLibro("tarea-" + tarea.getLibro().getNombre());

            tarea.setDescripcion(null);

        } catch (Exception ex) {
            anadirMensajeError("Error al registar");
        }
    }

    private void registrarCanal() {
        LOG.info("Dentro de registrarCanal: " + "tarea-" + tarea.getLibro().getNombre());
        final String libro = tarea.getLibro().getNombre();
        final String canalAux = canalesController.obtnereCanalPorLibro("tarea-" + libro);

        canal = "/" + "tarea-" + libro;

        if (canalAux == null) {
            canalesController.adicionarCanalParaLibro("tarea-" + libro, canal);
        }
    }

    private void comunicarseConCanalDeLibro(String libro) {
        LOG.info("Dentro de comunicarseConCanalDeLibroTarea...");
        final String canalLibro = canalesController.obtnereCanalPorLibro(libro);
        LOG.info("El canal Tarea es: " + canalLibro);

        if (canalLibro != null && !canalLibro.isEmpty()) {
            PushContext pushContext = PushContextFactory.getDefault().getPushContext();
            pushContext.push(canalLibro, null);
        }
    }

    public void cargarTareasParaVotar() {
        LOG.info("Dentro de cargarTareasParaVotar...");
        final Usuario usuario = usuarioFacade.buscarUsuarioPorNick(loginController.getNick());

        listaVotosTareas = votosTareaFacade.cargarVotosPorUsuarioYlibro(usuario.getIdUsuario(), tarea.getLibro().getIdLibro());

        for (Tarea t : listaTareas) {
            if (!VotosTareaNegocio.validarExistenciaEnLista(listaVotosTareas, t)) {
                final VotosTarea votosTarea = new VotosTarea();

                votosTarea.setTarea(t);
                votosTarea.setUsuario(usuario);

                listaVotosTareas.add(votosTarea);
            }
        }
    }

    public void realizarVotacion() {
        LOG.info("Dentro de realizarVotacion...");
        try {
            userTransaction.begin();

            for (VotosTarea votosTarea : listaVotosTareas) {
                if (votosTarea.getIdVotosTarea() == 0 && votosTarea.getValor() != null) {
                    votosTareaFacade.create(votosTarea);
                }
            }
            commitTransaction();

            anadirMensajeInfo("Votación exitosa");

            listaVotosTareas.clear();

            JsfUtil.ejecutarJavaScript("wvVotacionTareas.hide();");

        } catch (Exception ex) {
            anadirMensajeError("Error en el proceso de votación");
        }
    }

    public void cargarTareasPorCubrir() {
        LOG.info("Dentro de cargarTareasPorCubrir...");

        listaTareasPorCubrir = votosTareaFacade.cargarVotosPorCubrir(tarea.getLibro().getIdLibro());

        LOG.info("Tamanio listaTareasPorCubrir: " + listaTareasPorCubrir.size());
    }

    //Getters y Setters
    public CanalesController getCanalesController() {
        return canalesController;
    }

    public void setCanalesController(CanalesController canalesController) {
        this.canalesController = canalesController;
    }

    public LoginController getLoginController() {
        return loginController;
    }

    public void setLoginController(LoginController loginController) {
        this.loginController = loginController;
    }

    public Tarea getTarea() {
        return tarea;
    }

    public void setTarea(Tarea tarea) {
        this.tarea = tarea;
    }

    public List<Tarea> getListaTareas() {
        return listaTareas;
    }

    public void setListaTareas(List<Tarea> listaTareas) {
        this.listaTareas = listaTareas;
    }

    public List<Tarea> getListaTareasPorCubrir() {
        return listaTareasPorCubrir;
    }

    public void setListaTareasPorCubrir(List<Tarea> listaTareasPorCubrir) {
        this.listaTareasPorCubrir = listaTareasPorCubrir;
    }

    public List<VotosTarea> getListaVotosTareas() {
        return listaVotosTareas;
    }

    public void setListaVotosTareas(List<VotosTarea> listaVotosTareas) {
        this.listaVotosTareas = listaVotosTareas;
    }

    public String getCanal() {
        return canal;
    }

    public void setCanal(String canal) {
        this.canal = canal;
    }

    //Clonar
    private Tarea clonarObjeto(Tarea objeto) {
        Tarea objetoClonado = null;
        if (objeto == null) {
            return null;
        } else {
            try {
                objetoClonado = (Tarea) SerializationUtils.clone(objeto);
            } catch (Exception e) {
                objetoClonado = null;
            } finally {
                return objetoClonado;
            }
        }
    }

    @FacesConverter(forClass = Tarea.class)
    public static class TareaControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            TareaController controller = (TareaController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "tareaController");
            return controller.tareaFacade.find(getKey(value));
        }

        int getKey(String value) {
            int key;
            key = Integer.parseInt(value);
            return key;
        }

        String getStringKey(int value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Tarea) {
                Tarea o = (Tarea) object;
                return getStringKey(o.getIdTarea());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + Tarea.class.getName());
            }
        }
    }
}
